mod serial;
mod x_api;
use common::serial::api_descriptor::ServiceApiDescriptor;
use common::service::sys_service_api::ServiceKey;
use common::utils::file_utils;
use common::utils::string_utils::extract_version;
use pyo3::prelude::*;
use pyo3::types::PyList;
use pyo3::wrap_pyfunction;
use semver::Version;
use std::collections::HashMap;
use std::sync::Arc;
use structopt::StructOpt;
use x_api::*;

// 加载 dsl
async fn load_dsc() {
    let cur_dir = std::env::current_dir().unwrap();
    let cur_dir = cur_dir.to_str().unwrap();
    let proto_path = format!("{}/protos", cur_dir);
    let file_list = file_utils::get_file_list(&proto_path).await;
    if file_list.is_err() {
        panic!(
            "获取路径 {} 下的 api 描述文件列表失败:{:?}！",
            proto_path,
            file_list.err()
        );
    }
    let file_list = file_list.unwrap();
    let source_file_name = file_list
        .iter()
        .enumerate()
        .find(|(_, ele)| ele.starts_with("source_api"))
        .map(|(_, ele)| ele);

    if source_file_name.is_none() {
        panic!("protos 目录 缺少 source_api 描述文件！");
    }

    let source_file_name = source_file_name.unwrap();
    let new_source_version = source_file_name
        .replace("source_api", "version")
        .replace(".proto", "");
    let dxc_version = extract_version(&new_source_version);

    if dxc_version.is_none() {
        panic!("无法识别：{} 版本号！", source_file_name);
    }
    let str_version = dxc_version.unwrap().replace("_", ".");
    let version = Version::parse(&str_version);
    if version.is_err() {
        panic!("无法识别：{} 版本号:{}！", source_file_name, str_version);
    }
    // 这里不正确，需要获取
    let proto_file_path = format!("{}/protos/{}", cur_dir, source_file_name);

    let is_source_api_exist = file_utils::is_file_exist(proto_file_path.as_ref()).await;
    if !is_source_api_exist {
        panic!("protos 目录 缺少 source_api.proto 文件！");
    }
    let service_api_descriptor = ServiceApiDescriptor::load_with_include_path(
        proto_file_path.as_str(),
        proto_path.as_str(),
        true,
    );

    let service_api_descriptor = service_api_descriptor.unwrap();

    unsafe {
        DESCRIPTOR.as_mut_ptr().write(service_api_descriptor);
    }

    unsafe {
        IMPORTSERVICE_DESCRIPTOR.as_mut_ptr().write(HashMap::new());
    }
    // 加载 import
    for filename in file_list {
        if !filename.starts_with("import_api_") {
            continue;
        }
        let sdk_file_full_path = format!("{}/{}", proto_path, filename);
        let service_api_descriptor = ServiceApiDescriptor::load_with_include_path(
            sdk_file_full_path.as_str(),
            cur_dir,
            true,
        )
        .expect("加载导入 Api 错误");
        //
        // 是横杠
        let dxc_name = filename.replace("import_api_", "").replace(".proto", "");

        let dxc_version = extract_version(&dxc_name);
        if dxc_version.is_none() {
            panic!("无法识别：{} 版本号！", filename);
        }
        let dxc_version = dxc_version.unwrap().replace("_", ".");
        let version = Version::parse(&dxc_version);

        if version.is_err() {
            panic!("无法识别：{} 版本号:{}", filename, &dxc_version);
        }
        let dxc_name = dxc_name.replace("_", ".");
        //
        unsafe {
            IMPORTSERVICE_DESCRIPTOR
                .assume_init_mut()
                .insert(dxc_name, Arc::new(Box::new(service_api_descriptor)));
        }
    }

    //
}

#[pyfunction]
fn init(py: Python) -> PyResult<&PyAny> {
    //
    pyo3_asyncio::tokio::future_into_py(py, async {
        load_dsc().await;
        // 获取到 dispatch 函数
        service::init();
        //
        Python::with_gil(|py| {
            let service_module = py.import("service").expect("获取不到 service");
            let service_name = unsafe { DESCRIPTOR.assume_init_ref().service_name() };
            let service_class = service_module.getattr(service_name).unwrap();
            let service_instance = service_class.call((), None).unwrap();
            let _ = py
                .import("builtins")
                .unwrap()
                .dict()
                .set_item("SERVICE", service_instance);
            //

            // 连接到 xport
            tokio::spawn(async {
                ipc::connect_to_xport().await;
            });
        });

        Ok(())
    })
}

#[pyfunction]
fn start(py: Python) {
    let sys_module = py.import("sys").unwrap();
    let syspath: &PyList = match sys_module
        .getattr("path")
        .and_then(|p| p.downcast::<PyList>().map_err(|e| PyErr::from(e)))
    {
        Ok(path) => path,
        Err(e) => {
            panic!("获取 sys.path 失败");
        }
    };
    syspath.insert(0, "./src/x_com").unwrap();

    let asyncio_module = py.import("asyncio").expect("获取不到 service");
    let xport_core = py.import("xport_core").unwrap();
    let coroutine = xport_core.call_method0("lanuch").unwrap();
    asyncio_module.call_method1("run", (coroutine,)).unwrap();
}

#[pymodule]
fn x_com_python_lib(py: Python, m: &PyModule) -> PyResult<()> {
    //
    // 这里是在同一条线程执行的
    m.add_function(wrap_pyfunction!(service_name, m)?)?;
    //

    let log_submodule = PyModule::new(py, "log")?;

    log_submodule.add_function(wrap_pyfunction!(log::level, m)?)?;
    log_submodule.add_function(wrap_pyfunction!(log::output, m)?)?;
    //
    let xport_api_submodule = PyModule::new(py, "xport_api")?;

    xport_api_submodule.add_function(wrap_pyfunction!(xport_api::send_message, m)?)?;
    xport_api_submodule.add_function(wrap_pyfunction!(xport_api::get_all_conn_id, m)?)?;
    xport_api_submodule.add_function(wrap_pyfunction!(xport_api::get_channel_id_by_conn_id, m)?)?;
    xport_api_submodule.add_function(wrap_pyfunction!(xport_api::resopnse_message, m)?)?;
    //
    let http_api_submodule = PyModule::new(py, "http_api")?;

    http_api_submodule.add_function(wrap_pyfunction!(http_api::send_http_request, m)?)?;

    m.add_class::<xport_future::PyHttpRequest>()?;
    m.add_class::<xport_future::PyServiceKey>()?;
    //
    m.add_function(wrap_pyfunction!(gen_id, m)?)?;
    //
    m.add_function(wrap_pyfunction!(init, m)?)?;
    m.add_function(wrap_pyfunction!(start, m)?)?;

    m.add_submodule(log_submodule)?;
    m.add_submodule(xport_api_submodule)?;
    m.add_submodule(http_api_submodule)?;

    let sys_module = py.import("sys")?;
    //
    let argv: Vec<String> = sys_module.getattr("argv")?.extract()?;
    let boot_args = BootArgs::from_iter(argv);
    let mut self_service_key = ServiceKey::default();
    self_service_key.dxc_name = boot_args.dxc_name.clone();
    self_service_key.dxc_version = boot_args.dxc_version.clone();
    self_service_key.service_name = boot_args.service_name.clone();
    unsafe {
        BOOT_ARGS.as_mut_ptr().write(boot_args);

        SELF_SERVICE_KEY.as_mut_ptr().write(self_service_key);
    }
    Ok(())
}
